using System;
using Microsoft.SPOT;
using SecretLabs.NETMF.Hardware.Netduino;
using NetduinoHappyHour.Util;

namespace NetduinoHappyHour.Hardware
{
    /// <summary>
    /// Class to display messages on LCD.
    /// Using MicroLiquidCrystal Library from http://microliquidcrystal.codeplex.com/
    /// GioLcdTransferProvider obtained from MicroLiquidCrystal Library.
    /// I2CLcdTransferProvider added by me to MicroLiquidCrystal Library
    /// Written by Salvador Richter
    /// Free to use by GNU Lesser General Public License (LGPL), please attribute credit
    /// </summary>
    public class DisplayMessage : IExecutable
    {
        //Size of the LCD Display as Const
        private const int LINE_SIZE = 2;
        private const int COLUMN_SIZE = 16;
        static MicroLiquidCrystal.ILcdTransferProvider _lcdProvider;
        static MicroLiquidCrystal.Lcd _lcd;
        public string TextLine1 { get; set; }
        public string TextLine2 { get; set; }

        /// <summary>
        /// Base constructor to display single line message on LCD Board
        /// If message length exceeds LCD width, line is wrapped and end of message is shown on second line on display
        /// Uses GPIO PIN D4 to D9 or I2C Pins (I2C Pins vary on different netduino boards)
        /// </summary>
        /// <param name="message">Message to be shown on display</param>
        public DisplayMessage(string line1)
            : this(line1, "")
        {
            if (line1 == null)
            {
                line1 = "NoMessage";
            }

            if (line1.Length > COLUMN_SIZE)
            {
                this.TextLine2 = line1.Substring(line1.Length - COLUMN_SIZE);
            }
        }

        /// <summary>
        /// Base constructor to display double line message on LCD Board
        /// Uses GPIO PIN D4 to D9 or I2C Pins (I2C Pins vary on different netduino boards)
        /// </summary>
        /// <param name="message">Message to be shown on display</param>
        public DisplayMessage(string line1, string line2)
        {
            TextLine1 = line1;
            TextLine2 = line2;

            // Initialize if needed
            if (_lcd == null &&
                SystemConfig.Instance().DisplayType != SystemConfig.Display.None)
            {
                try
                {
                    if (SystemConfig.Instance().DisplayType == SystemConfig.Display.I2C)
                    {
                        // I2CBus of Netduino is on A4+A5
                        SystemConfig.Instance().RegisterPin(Pins.GPIO_PIN_A4, GetType().Name);
                        SystemConfig.Instance().RegisterPin(Pins.GPIO_PIN_A5, GetType().Name);
                        _lcdProvider = new MicroLiquidCrystal.I2CLcdTransferProvider();
                    }
                    if (SystemConfig.Instance().DisplayType == SystemConfig.Display.Parallel)
                    {
                        SystemConfig.Instance().RegisterPin(Pins.GPIO_PIN_D4, GetType().Name);
                        SystemConfig.Instance().RegisterPin(Pins.GPIO_PIN_D5, GetType().Name);
                        SystemConfig.Instance().RegisterPin(Pins.GPIO_PIN_D6, GetType().Name);
                        SystemConfig.Instance().RegisterPin(Pins.GPIO_PIN_D7, GetType().Name);
                        SystemConfig.Instance().RegisterPin(Pins.GPIO_PIN_D8, GetType().Name);
                        SystemConfig.Instance().RegisterPin(Pins.GPIO_PIN_D9, GetType().Name);
                        //Pins according to LCD Sield from AVT-1615 http://sklep.avt.pl/p/pl/493710/avtduino+_lcd+wyswietlacz+dla+arduino+-+zestaw+zmontowany+i+uruchomiony.html
                        _lcdProvider = new MicroLiquidCrystal.GpioLcdTransferProvider(Pins.GPIO_PIN_D8, Pins.GPIO_PIN_D9, Pins.GPIO_PIN_D4, Pins.GPIO_PIN_D5, Pins.GPIO_PIN_D6, Pins.GPIO_PIN_D7);
                    }
                    _lcd = new MicroLiquidCrystal.Lcd(_lcdProvider);
                    _lcd.Begin(COLUMN_SIZE, LINE_SIZE);
                }
                catch (Exception Ex)
                {
                    SystemStatus.Instance().AddMessage("Error initializing Display, set Display.None" + Ex);
                    if (SystemConfig.Instance().DisplayType == SystemConfig.Display.I2C)
                    {
                        SystemConfig.Instance().DeregisterPin(Pins.GPIO_PIN_A4);
                        SystemConfig.Instance().DeregisterPin(Pins.GPIO_PIN_A5);
                    }
                    if (SystemConfig.Instance().DisplayType == SystemConfig.Display.Parallel)
                    {
                        SystemConfig.Instance().DeregisterPin(Pins.GPIO_PIN_D4);
                        SystemConfig.Instance().DeregisterPin(Pins.GPIO_PIN_D5);
                        SystemConfig.Instance().DeregisterPin(Pins.GPIO_PIN_D6);
                        SystemConfig.Instance().DeregisterPin(Pins.GPIO_PIN_D7);
                        SystemConfig.Instance().DeregisterPin(Pins.GPIO_PIN_D8);
                        SystemConfig.Instance().DeregisterPin(Pins.GPIO_PIN_D9);
                    }
                    SystemConfig.Instance().DisplayType = SystemConfig.Display.None;
                }
            }
        }

        public void Execute()
        {
            if (SystemConfig.Instance().DisplayType == SystemConfig.Display.None ||
                _lcd == null)
            {
                return;
            }

            _lcd.Clear();
            _lcd.SetCursorPosition(0, 0);
            _lcd.Write(PrepareDisplayValue(TextLine1));
            _lcd.SetCursorPosition(0, 1);
            _lcd.Write(PrepareDisplayValue(TextLine2));
        }


        /// <summary>
        /// checks string on length, max length depends on display type, actual COLUMN_SIZE
        /// to long values are cut off and appendet with ".."
        /// null proof
        /// </summary>
        /// <param name="Value">string Value to be checked</param>
        private string PrepareDisplayValue(string value)
        {
            if (value == null)
            {
                return "";
            }
            else if (value.Length <= COLUMN_SIZE)
            {
                return value;
            }
            else
            {
                return value.Substring(0, COLUMN_SIZE - 2) + "..";
            }
        }

        /// <summary>
        /// Clears the LCD, no call to Execute() required.
        /// </summary>
        public void Clear()
        {
            if (_lcd != null)
            {
                _lcd.Clear();
            }
        }
    }
}

